/***
 * @Description: socket结构的RAW类型的数据结构和函数定义的头文件
 * @Author: Liverpool
 * @Date: 2024-09-24 01:17:30
 * @LastEditTime: 2024-09-24 01:41:37
 * @LastEditors: Liverpool
 */
#include "raw.h"
#include "sock.h"
#include "debug.h"
#include "memory_block.h"
#include "ipv4.h"
#include "socket.h"

// 变量定义区
static D_Raw raw_table[RAW_MAX_NUM];
static D_MemoryBlock raw_memoryblock; // raw链表的内存管理模块
static D_List raw_list;               // raw链表

/***
 * @description: raw结构的数据发送函数,sendto函数的raw操作
 * @Author: Liverpool
 * @Date: 2024-10-02 02:32:55
 * @return {*}
 * @param {_sock_t} *sock sokcet套接字地址
 * @param {void} *buf 发送的数据内存地址
 * @param {size_t} len 发送的数据长度
 * @param {int} flags 发送的标志位
 * @param {x_sockaddr} *dest 发送的目标地址
 * @param {x_socklen_t} dest_len 发送的目标地址长度
 * @param {ssize_t} *result_len 返回发送的数据数量
 */
static net_err_t raw_sendto(struct _sock_t *sock, const void *buf, size_t len, int flags, const struct x_sockaddr *dest, x_socklen_t dest_len, ssize_t *result_len)
{
    // 进行目的IP地址转化
    D_IP_ADDR dest_ip;
    struct x_sockaddr_in *addr = (struct x_sockaddr_in *)dest;
    ipaddr_from_buf(&dest_ip, addr->sin_addr.addr_array);
    // 对IP地址进行检查
    if (!ip_addr_is_any(&sock->remote_ip) && ipaddr_is_equal(&sock->remote_ip, &dest_ip))
    {
        // 需要判断remote_ip和dest_ip相等
        debug_error(Debug_RAW, "dest ip error...");
        return NET_ERR_PARAM;
    }
    // 分配packet数据包
    D_Packet *pktbuf = packet_alloc((int)len);
    if (!pktbuf)
    {
        debug_error(Debug_RAW, "no packet buffer...");
        return NET_ERR_MEMORY;
    }
    net_err_t err = packet_write(pktbuf, (uint8_t *)buf, (int)len);
    if (err < 0)
    {
        debug_error(Debug_RAW, "writr to packet buffer failed...");
        goto end_send_to;
    }
    err = ipv4_out(sock->protocol, &dest_ip, &(net_interface_get_default())->ipaddr, pktbuf);
    if (err < 0)
    {
        debug_error(Debug_RAW, "raw send failed...");
        goto end_send_to;
    }
    *result_len = (ssize_t)len;
    return err;
end_send_to: // 释放分配的数据包
    packet_free(pktbuf);
    return err;
}

/***
 * @description: raw结构的数据发送函数,sock的raw结构的recvfrom操作函数
 * @Author: Liverpool
 * @Date: 2024-10-02 02:32:55
 * @return {*}
 * @param {_sock_t} *sock sokcet套接字地址
 * @param {void} *buf 接收的数据内存地址
 * @param {size_t} len 接收的数据长度
 * @param {int} flags 接收的标志位
 * @param {x_sockaddr} *dest 接收的目标地址
 * @param {x_socklen_t} dest_len 接收的目标地址长度
 * @param {ssize_t} *result_len 返回接收的数据数量
 */
static net_err_t raw_recvfrom(struct _sock_t *sock, void *buf, size_t len, int flags, const struct x_sockaddr *dest, x_socklen_t *dest_len, ssize_t *result_len)
{
    D_Raw *raw = (D_Raw *)sock;
    D_ListNode *first = list_remove_first(&raw->recv_list);
    // 检查raw的等待队列中是否由数据
    if (!first)
    {
        // 没有数据那就进行等待
        *result_len = 0;
        return NET_ERR_MEED_WAIT;
    }
    // 对数据进行解析
    D_Packet *packet = list_entry(first, D_Packet, node);
    D_IPv4_Header *iphdr = (D_IPv4_Header *)packet_firstBlock_data(packet);
    // 对端的IP信息进行读取和赋值
    struct x_sockaddr_in *addr = (struct x_sockaddr_in *)dest;
    plat_memset(addr, 0, sizeof(struct x_sockaddr_in));
    addr->sin_family = AF_INET;
    addr->sin_port = 0;
    plat_memcpy(&addr->sin_addr, iphdr->src_ip, IPV4_ADDR_SIZE);
    // 获取需要读取的长度
    int size = (packet->total_size > (int)len) ? (int)len : packet->total_size;
    packet_reset_access(packet); // 重定位packet的数据指针位置
    // 进行数据的读取
    net_err_t err = packet_read(packet, buf, size);
    if (err < 0)
    {
        packet_free(packet);
        debug_error(Debug_RAW, "packer buf read error...");
        return err;
    }
    packet_free(packet);
    *result_len = size;
    return NET_ERR_OK;
}

/***
 * @description: raw模块初始化函数
 * @Author: Liverpool
 * @Date: 2024-09-24 01:48:46
 * @return {*} 初始化过程中的错误
 */
net_err_t raw_init(void)
{
    debug_info(Debug_RAW, "raw_init...");
    list_init(&raw_list);
    memory_block_init(&raw_memoryblock, raw_table, sizeof(D_Raw), RAW_MAX_NUM, Locker_Self);
    debug_info(Debug_RAW, "raw_init done...");
    return NET_ERR_OK;
}

/***
 * @description: raw sock结构的创建
 * @Author: Liverpool
 * @Date: 2024-09-26 00:41:17
 * @return {*} 创建的sock的指针
 * @param {int} family 协议族
 * @param {int} protocol 协议
 */
D_Sock *raw_create(int family, int protocol)
{
    static const D_Sock_Operation raw_ops = {
        .sendto = raw_sendto,
        .recvfrom = raw_recvfrom,
        .setopt = sock_setopt,
    };
    // 分配raw结构
    D_Raw *raw = memory_block_alloc(&raw_memoryblock, -1);
    // 初始化raw
    if (!raw)
    {
        debug_info(Debug_RAW, "no  raw sock...");
        return (D_Sock *)0;
    }
    net_err_t err = sock_init((D_Sock *)raw, family, protocol, &raw_ops);
    raw->base.recv_wait = &raw->recv_wait;
    list_init(&raw->recv_list);
    if (sock_wait_init(raw->base.recv_wait) < 0)
    {
        debug_error(Debug_RAW, "create receive wait failed...");
        goto create_failed;
    }
    if (err < 0)
    {
        debug_info(Debug_RAW, "create raw failed...");
        memory_block_free(&raw_memoryblock, raw); // 释放内存分块空间
        return (D_Sock *)0;
    }
    list_insert_last(&raw_list, &raw->base.node); // 插入raw链表
    return (D_Sock *)raw;
create_failed:
    sock_uninit(&raw->base);
    return (D_Sock *)0;
}

/***
 * @description: （静态函数）寻找所对应的raw结构
 * @Author: Liverpool
 * @Date: 2024-10-11 00:41:17
 * @return {*} 返回找到raw结构的内存地址
 * @param {D_IP_ADDR} *src 数据包的源IP地址
 * @param {D_IP_ADDR} *dest 数据包的目的IP地址
 * @param {int} protocol 数据包的协议类型
 */
static D_Raw *raw_find(D_IP_ADDR *src, D_IP_ADDR *dest, int protocol)
{
    D_ListNode *node;
    list_for_each_node(node, &raw_list)
    {
        D_Raw *raw = (D_Raw *)list_entry(node, D_Sock, node);
        if (raw->base.protocol && (raw->base.protocol != protocol))
        {
            continue;
        }
        if (!ip_addr_is_any(&raw->base.remote_ip) && !ipaddr_is_equal(&raw->base.remote_ip, src))
        {
            continue;
        }
        if (!ip_addr_is_any(&raw->base.local_ip) && !ipaddr_is_equal(&raw->base.local_ip, dest))
        {
            continue;
        }
        return raw;
    }
    return (D_Raw *)0;
}

/***
 * @description: 套接字raw类形的输出处理函数
 * @Author: Liverpool
 * @Date: 2024-10-11 00:12:41
 * @return {*}
 * @param {D_Packet} *pkt 输入的数据包内存地址
 */
net_err_t raw_in(D_Packet *pkt)
{
    D_IPv4_Header *iphdr = (D_IPv4_Header *)packet_firstBlock_data(pkt); // 获取IPv4的头
    D_IP_ADDR src, dest;
    ipaddr_from_buf(&dest, iphdr->dest_ip);
    ipaddr_from_buf(&src, iphdr->src_ip);
    D_Raw *raw = raw_find(&src, &dest, iphdr->protocol); // 对RAW结构进行查找
    if (!raw)
    {
        debug_Warning(Debug_RAW, "no raw for this packet");
        return NET_ERR_UNREACH;
    }
    // 进行输入处理
    if (list_get_count(&raw->recv_list) < D_RAW_MAX_RECV_NUM)
    {
        list_insert_last(&raw->recv_list, &pkt->node);          // 插入在接收队列最后
        sock_wakeup((D_Sock *)raw, SOCK_WAIT_READ, NET_ERR_OK); // 唤醒sock等待结构
    }
    else
    {
        packet_free(pkt); // 如果接收队列已满，那就直接释放数据包
    }

    return NET_ERR_OK;
}